﻿//---------------------------------------------------------------------------
#pragma hdrstop

#include "stdafx.h"
#include "PlayTimer.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)

UINT BarTimerID, PreOffTimerID, ComposeTimerID;    //定义定时器句柄
bool BarTimer_Enabled = false;
bool PreOffTimer_Enabled = false;
bool ComposeTimer_Enabled = false;
bool BarTimerProcess = false;
int TimerAccuracy;

void TimerBeginPeriod()
{
	TIMECAPS timecaps;

	//从系统获得关于定时器服务能力的信息，
	//分辨率不能超出系统许可值（1到16毫秒）
	if (timeGetDevCaps(&timecaps,sizeof(TIMECAPS))==TIMERR_NOERROR)
	{
		TimerAccuracy = Min( Max(timecaps.wPeriodMin, Accuracy), timecaps.wPeriodMax);
	}

	timeBeginPeriod(TimerAccuracy);
}

void TimerEndPeriod()
{
	timeEndPeriod(TimerAccuracy);  //清除定时器分辨率
}

void BarTimerStart()
{
	BarTimer_Enabled = true;
	int Interval = ( 60000 / ActualTempo*4 ) / OneSectionNoteNum - MatchDelay; //3~7

	BarTimerID = timeSetEvent(Interval, TimerAccuracy, &BarTimerCallProc, 1, TIME_PERIODIC);
}

void BarTimerStop()
{
    BarTimer_Enabled = false;
	timeKillEvent(BarTimerID);        //删除定时器事件
}

void PreOffTimerStart()
{
	PreOffTimer_Enabled = true;
	int Interval = ( 60000 / ActualTempo*4 ) / OneSectionNoteNum - MatchDelay - SendDelay;
	Interval = Interval > 1 ? Interval : 1;

	//TIME_ONESHOT：uDelay毫秒后只产生一次事件
	PreOffTimerID = timeSetEvent(Interval, TimerAccuracy, &PreOffTimerCallProc, 1, TIME_ONESHOT);
}

void PreOffTimerStop()
{
    PreOffTimer_Enabled = false;
	timeKillEvent(PreOffTimerID);        //删除定时器事件
}

void ComposeTimerStart()
{
	ComposeTimer_Enabled = true;
	//int Interval = ( 60000 / ActualTempo*4 ) / OneSectionNoteNum - MatchDelay; //3~7
    int Interval = 10;
	ComposeTimerID = timeSetEvent(Interval, TimerAccuracy, &ComposeTimerCallProc, 1, TIME_ONESHOT);
}

void ComposeTimerStop()
{
	ComposeTimer_Enabled = false;
	timeKillEvent(ComposeTimerID);        //删除定时器事件
}

void PASCAL BarTimerCallProc(UINT TimerID, UINT msg,DWORD dwUser, DWORD dwa,DWORD dwb)
{
	BarTimerProcess = true;

	if( TimePosition == -OneSectionNoteNum )  //第一次按下開始按鈕
	{
		ActualTempo = CurrentTempo;

		SelectGuitarBassGroovePart();
		//開始打鼓
		GrooveFill = 1;
		FormMixer->Port_22_Vol_Bar->Position = Form1->Groove_Vol_Bar->Position;
		FormMixer->Port_23_Vol_Bar->Position = 127 - 0;
		MidiNoteOn(22, GroovePartsResult, 100);
		MidiNoteOn(23, GroovePartsResult, 100);
		MidiNoteOff(22, GroovePartsResult, 100);
		MidiNoteOff(23, GroovePartsResult, 100);
        //打開Bass
		FormMixer->Port_21_Vol_Bar->Position = Form1->Bass_Vol_Bar->Position;

        ResetAllNote();  //重設所有Note
		GenerateChordSetAll();
		WriteAllChord();

		TimePosition = 0;
		PlayCurrentNotation(true);   //演奏當下的所有音符
		//ResetOneTimeNoGuitar(TimePosition);  //演奏下去了，把他重設
		TimePosition = -OneSectionNoteNum;

		TimePosition ++;

		ComposeTimerStart();
		return;
	}
	else if(TimePosition < 0)
	{
		TimePosition ++;
		return;
	}
	else if( (TimePosition % (OneSectionNoteNum*3) == 0 ) && (TimePosition != 0) )   //第四小節過門
	{
    	//開始打鼓
		GrooveFill = 1;
		FormMixer->Port_22_Vol_Bar->Position = Form1->Groove_Vol_Bar->Position;
		FormMixer->Port_23_Vol_Bar->Position = 127 - 0;
		MidiNoteOn(22, GroovePartsResult, 100);
		MidiNoteOn(23, GroovePartsResult, 100);
		MidiNoteOff(22, GroovePartsResult, 100);
		MidiNoteOff(23, GroovePartsResult, 100);
	}

	///////////////////////每半個小節更新速度/////////////////////////
	//int ChangeTempoFreq = ActualTempo - CurrentTempo > 10 ? 1 : 2;    //如果從很快變成很慢，怕跑掉，就先一個小節更新一次就好
	int ChangeTempoFreq = ActualTempo > 150 ? 1 : 2;    //如果從很快變成很慢，怕跑掉，就先一個小節更新一次就好
	if(TimePosition % (OneSectionNoteNum/ChangeTempoFreq) == 0)
	{
		if( ActualTempo != Form1->TempoBar->Position )  //如果現在真正在執行的沒有match再改
		{
			ActualTempo = Form1->TempoBar->Position;

			SetNuendoTempo( ActualTempo );
			BarTimerStop();
			BarTimerStart();
		}
	}

	if(TimePosition % OneSectionNoteNum == OneSectionNoteNum-1)
	{
		PreOffTimerStart();
	}

	if ( TimePosition == 0 )  //如果是一開始預先做的事
	{
		//MuteAllNote();   //全部靜音
		//ResetAllNote();  //重設所有Note

		//計算出所有順階和弦
		//CalculateDiatonicChord(60, "M");

		//編排和弦
//		GenerateChordSetAll();
//		ComposeTimerStart();
//		WriteAllChord();
	}

	if(TimePosition % OneSectionNoteNum == 0) //一小節開頭寫在裡面
	{
        //選擇伴奏方式
		SelectGuitarBassGroovePart();

		//打開Bass
		FormMixer->Port_21_Vol_Bar->Position = Form1->Bass_Vol_Bar->Position;

		if(NeedFill)
		{
			GrooveFill = 1;
			MidiNoteOn(22, GroovePartsResult, Form1->NoteVelocityBar->Position);
			MidiNoteOn(23, GroovePartsResult, Form1->NoteVelocityBar->Position);
			MidiNoteOff(22, GroovePartsResult, Form1->NoteVelocityBar->Position);
			MidiNoteOff(23, GroovePartsResult, Form1->NoteVelocityBar->Position);
			NeedFill = false;
		}
		else if(GrooveFill == 2)
		{
			MidiNoteOn(22, GroovePartsResult, Form1->NoteVelocityBar->Position);
			MidiNoteOff(22, GroovePartsResult, Form1->NoteVelocityBar->Position);
		}
		else if(GrooveFill == 1)
		{
			MidiNoteOn(23, GroovePartsResult, Form1->NoteVelocityBar->Position);
			MidiNoteOff(23, GroovePartsResult, Form1->NoteVelocityBar->Position);
		}
	}

	PlayCurrentNotation(false);   //演奏當下的所有音符
	ResetOneTimeNoGuitar(TimePosition);  //演奏下去了，把他重設

	//Form1->Caption = TimePosition;
	//更新時間軸
	//每八小節檢查一次是不是要重跑換調性
	if( (TimePosition % (OneSectionNoteNum*8) == OneSectionNoteNum*8-1) &&
		( (AllStartChord == 6 && AV_Point.x >= 0) || (AllStartChord == 1 && AV_Point.x < 0) )
	  )
	{
		//TimePosition = 0;  //時間軸歸0，讓他重跑一次
		TimePosition = 	-OneSectionNoteNum;
	}
	else
	{
		if ( TimePosition + 1 >= MaxNote )
		{
            //時間軸歸0
			//TimePosition = 0;
			TimePosition = 	-OneSectionNoteNum;
		}
		else
		{ TimePosition ++; }  //往前移動
	}

	BarTimerProcess = false;
}

void PASCAL PreOffTimerCallProc(UINT TimerID, UINT msg,DWORD dwUser, DWORD dwa,DWORD dwb)
{
	mes message;

	//Guitar Off
	for ( int PortNum = 13; PortNum <= 21; PortNum ++ )  //先跑Port
	{
		for ( int PitNum = MinPitchValue; PitNum < MaxPitchValue; PitNum ++ )  //跑所有音高
		{
			//if ( Notation[PortNum][TimePosition-1].Pitch[PitNum].Used )  //如果有要用到的訊號
			{
				//if ( Notation[PortNum][TimePosition-1].Pitch[PitNum].NoteOn ) //如果Note On
				{
					message.data[0] = 0x80;  // Note Off
					message.data[1] = PitNum;  //Pitch
					message.data[2] = Notation[PortNum][TimePosition-1].Pitch[PitNum].Volume;  //Volume

					midiOutShortMsg(device[PortNum], message.word);
				}
			}
		}
	}
	ResetOneTimeJustGuitar(TimePosition-1);

	FormMixer->Port_21_Vol_Bar->Position = 127-0;
	MidiNoteOn(21, 36, 100);  //Bass Off
	MidiNoteOff(21, 36, 100);

	if(NeedFill)
	{
		MidiNoteOn(22, 71, 100);  //Groove Off
		MidiNoteOff(22, 71, 100);
		MidiNoteOn(23, 71, 100);  //Groove2 Off
		MidiNoteOff(23, 71, 100);
		FormMixer->Port_22_Vol_Bar->Position = 127 - 0;
		FormMixer->Port_23_Vol_Bar->Position = Form1->Groove_Vol_Bar->Position;
		GrooveFill = 2;
	}
	if(GrooveFill == 1)
	{
		MidiNoteOn(22, 71, 100);  //Groove Off
		MidiNoteOff(22, 71, 100);
		FormMixer->Port_22_Vol_Bar->Position = 127 - 0;
		FormMixer->Port_23_Vol_Bar->Position = Form1->Groove_Vol_Bar->Position;
		GrooveFill = 2;
	}
	else if(GrooveFill == 2)
	{
		MidiNoteOn(23, 71, 100);  //Groove2 Off
		MidiNoteOff(23, 71, 100);
		FormMixer->Port_22_Vol_Bar->Position = Form1->Groove_Vol_Bar->Position;
		FormMixer->Port_23_Vol_Bar->Position = 127 - 0;
		GrooveFill = 1;
	}
}


void PASCAL ComposeTimerCallProc(UINT TimerID, UINT msg,DWORD dwUser, DWORD dwa,DWORD dwb)
{
	APEGA.Process(false, Chord_Record[0], Chord_Record[1], Chord_Record[2], Chord_Record[3]);
	Melody[0] = APEGA.Swarm.G_Best[0];
	APEGA.Process(false, Chord_Record[4], Chord_Record[5], Chord_Record[6], Chord_Record[7]);
	Melody[1] = APEGA.Swarm.G_Best[0];
	APEGA.Process(false, Chord_Record[8], Chord_Record[9], Chord_Record[10], Chord_Record[11]);
	Melody[2] = APEGA.Swarm.G_Best[0];
	APEGA.Process(false, Chord_Record[12], Chord_Record[13], Chord_Record[14], Chord_Record[15]);
	Melody[3] = APEGA.Swarm.G_Best[0];
	APEGA.Process(false, Chord_Record[16], Chord_Record[17], Chord_Record[18], Chord_Record[19]);
	Melody[4] = APEGA.Swarm.G_Best[0];

	Particle_Class Temp_Melody;
	int MaxFitness = -99999999;
	int Bar = 0;

	//Form 1
	Bar = 0;
	if( Melody[Bar].Phrase[0].Phrase_Fitness +
		Melody[Bar].Phrase[1].Phrase_Fitness +
		Melody[Bar].Phrase[2].Phrase_Fitness > MaxFitness )
	{
		MaxFitness = Melody[Bar].Phrase[0].Phrase_Fitness +
					 Melody[Bar].Phrase[1].Phrase_Fitness +
					 Melody[Bar].Phrase[2].Phrase_Fitness;

		Temp_Melody = Melody[Bar];
	}

	Bar = 1;
	if( Melody[Bar].Phrase[0].Phrase_Fitness +
		Melody[Bar].Phrase[1].Phrase_Fitness +
		Melody[Bar].Phrase[2].Phrase_Fitness > MaxFitness )
	{
		MaxFitness = Melody[Bar].Phrase[0].Phrase_Fitness +
					 Melody[Bar].Phrase[1].Phrase_Fitness +
					 Melody[Bar].Phrase[2].Phrase_Fitness;

		Temp_Melody = Melody[Bar];
	}

	Bar = 4;
	if( Melody[Bar].Phrase[0].Phrase_Fitness +
		Melody[Bar].Phrase[1].Phrase_Fitness +
		Melody[Bar].Phrase[2].Phrase_Fitness > MaxFitness )
	{
		MaxFitness = Melody[Bar].Phrase[0].Phrase_Fitness +
					 Melody[Bar].Phrase[1].Phrase_Fitness +
					 Melody[Bar].Phrase[2].Phrase_Fitness;

		Temp_Melody = Melody[Bar];
	}

	Melody[0].Phrase[0] = Temp_Melody.Phrase[0];
	Melody[0].Phrase[1] = Temp_Melody.Phrase[1];
	Melody[0].Phrase[2] = Temp_Melody.Phrase[2];
	Melody[1].Phrase[0] = Temp_Melody.Phrase[0];
	Melody[1].Phrase[1] = Temp_Melody.Phrase[1];
	Melody[1].Phrase[2] = Temp_Melody.Phrase[2];
	Melody[4].Phrase[0] = Temp_Melody.Phrase[0];
	Melody[4].Phrase[1] = Temp_Melody.Phrase[1];
	Melody[4].Phrase[2] = Temp_Melody.Phrase[2];


	//Form 2
	MaxFitness = -99999999;
	Bar = 2;
	if( Melody[Bar].Phrase[0].Phrase_Fitness +
		Melody[Bar].Phrase[1].Phrase_Fitness > MaxFitness )
	{
		MaxFitness = Melody[Bar].Phrase[0].Phrase_Fitness +
					 Melody[Bar].Phrase[1].Phrase_Fitness;

		Temp_Melody = Melody[Bar];
	}

	Bar = 3;
	if( Melody[Bar].Phrase[0].Phrase_Fitness +
		Melody[Bar].Phrase[1].Phrase_Fitness > MaxFitness )
	{
		MaxFitness = Melody[Bar].Phrase[0].Phrase_Fitness +
					 Melody[Bar].Phrase[1].Phrase_Fitness;

		Temp_Melody = Melody[Bar];
	}

	Melody[2].Phrase[0] = Temp_Melody.Phrase[0];
	Melody[2].Phrase[1] = Temp_Melody.Phrase[1];
	Melody[3].Phrase[0] = Temp_Melody.Phrase[0];
	Melody[3].Phrase[1] = Temp_Melody.Phrase[1];

	for(int i=0; i<5; i++)
	{
		WriteOneMelody(i, Melody[i]);
	}
}


